package com.greyshark.lib.bluetooth.utils

import android.content.Context
import android.text.TextUtils
import java.io.BufferedWriter
import java.io.File
import java.io.FileFilter
import java.io.FileWriter
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlin.math.abs

internal class Logger(context: Context) {

  //日志文件
  private var logFile: File? = null

  //日志路径文件夹
  private var fileDir = ""

  //日志路径
  private var filePath = ""

  //文件名前缀
  private var prefixFlag = "LOG"

  //文件名后缀
  private var suffixFlag = "log"

  //文件名
  private var fileName = prefixFlag

  //是否允许写入文件
  private var isWriteLog = true

  //清除日志时间天数
  private var expiredDay = 10

  init {
    fileName = "log"
    fileDir = context.getExternalFilesDir("log")?.absolutePath ?: ""
  }

  /**
   * 设置文件路径
   */
  fun setFileDirPath(dir: String?) {
    if (TextUtils.isEmpty(dir)) return
    val dirFile = File(dir!!)
    if (if (dirFile.exists()) dirFile.isDirectory else dirFile.mkdirs()) {
      fileDir = dir
    }
  }

  fun setPrefixFlag(flag: String?) {
    if (flag.isNullOrEmpty()) return
    prefixFlag = flag
  }

  /**
   * 设置是否允许写入文件
   */
  fun setIsWriteLog(isWriteLog: Boolean) {
    this.isWriteLog = isWriteLog
  }

  /**
   * 设置过期清除天数
   *
   * @param expiredDay
   */
  fun setExpiredDay(expiredDay: Int) {
    this.expiredDay = expiredDay
  }

  /**
   * 获取日志文件路径
   */
  fun getLogFilePath(): String {
    if (filePath.isEmpty()) createFile()
    return filePath
  }

  fun setSuffixFlag(flag: String?) {
    if (flag.isNullOrEmpty()) return
    suffixFlag = flag
  }

  /**
   * 创建文件
   */
  private fun createFile() {
    fileName = createFileName()
    try {
      logFile = File(File(fileDir), "$fileName.$suffixFlag")
      filePath = logFile!!.absolutePath
      if (!logFile!!.exists()) {
        logFile!!.createNewFile()
      }
    } catch (e: Exception) {
      e.printStackTrace()
    }
  }


  private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)

  private fun createFileName(): String {
    return prefixFlag + "_" + dateFormat.format(Date())
  }

  /**
   * 记录日志文件，用于测试版本apk记录日志
   *
   * @param tag
   * @param msg
   * @param isMainStyle 主风格
   */
  fun writeFile(tag: String?, msg: String?, append: Boolean = true, isMainStyle: Boolean = true) {
    if (!isWriteLog) return
    createFile()
    try {
      if (isMainStyle) {
        val mTag = if (TextUtils.isEmpty(tag)) "" else tag!!.lowercase(Locale.getDefault())
        val buffer = StringBuffer()
        buffer.append(logTime())
        buffer.append(" ----> ")
        buffer.append(mTag)
        buffer.append(" ")
        for (i in mTag.length..24) {
          buffer.append("-")
        }
        buffer.append("> ")
        buffer.append(msg)
        buffer.append("\r\n")
        writeFileFromString(logFile, buffer.toString(), append)
      } else {
        val buffer = StringBuffer()
        if (msg != null) buffer.append(msg)
        writeFileFromString(logFile, buffer.toString(), append)
      }
    } catch (e: Exception) {
      e.printStackTrace()
    }
  }

  private val logTimeDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS", Locale.ENGLISH)

  private fun logTime(): String? {
    return logTimeDateFormat.format(Date())
  }

  /**
   * 读取当前日志内容
   */
//    fun readLogContent(): String? {
//        createFile()
//        return FileIOUtils.readFile2String(logFile)
//    }


  /**
   * 字符串内容写入文件
   */
  fun writeFileFromString(
    file: File?,
    content: String?,
    append: Boolean
  ): Boolean {
    if (file == null || content == null) return false
    if (!file.isFile || !file.exists()) {
      return false
    }
    var bw: BufferedWriter? = null
    return try {
      bw = BufferedWriter(FileWriter(file, append))
      bw.write(content)
      true
    } catch (e: IOException) {
      e.printStackTrace()
      false
    } finally {
      try {
        bw?.close()
      } catch (e: IOException) {
        e.printStackTrace()
      }
    }
  }


  //region 清缓存
  /**
   * 清除过期文件
   * 保留expiredDay天前的日志
   */
  fun clearExpiredFile() {
    try {
      val logDir = File(fileDir)
      val logFiles = listFilesInDirWithFilterInner(
        logDir,
        { pathname ->
          //取文件夹内所有log txt 文件
          pathname != null
              && (pathname.absolutePath.endsWith("txt") || pathname.absolutePath.endsWith("log"))
        },
        false
      )
      if (logFiles != null) {
        for (i in logFiles.indices) {
          val fileNameDate = getFileNameNoExtension(
            logFiles[i].absolutePath
          ).replace(
            prefixFlag + "_",
            ""
          )
          val fileTime = dateFormat.parse(fileNameDate)?.time ?: 0L
          val expired =
            abs(System.currentTimeMillis() - fileTime) > expiredDay * 24 * 60 * 60 * 1000L
          if (expired) {
            val isDel = logFiles[i].isFile && logFiles[i].delete()
          }
        }
      }
    } catch (e: Exception) {
      e.printStackTrace()
    }
  }

  private fun listFilesInDirWithFilterInner(
    dir: File?,
    filter: FileFilter,
    isRecursive: Boolean
  ): List<File>? {
    try {
      val list: MutableList<File> = ArrayList()
      if (!(dir != null && dir.exists() && dir.isDirectory)) return list
      val files = dir.listFiles()
      if (files != null && files.isNotEmpty()) {
        for (file in files) {
          if (filter.accept(file)) {
            list.add(file)
          }
          if (isRecursive && file.isDirectory) {
            val subList = listFilesInDirWithFilterInner(file, filter, true)
            if (subList != null) {
              list.addAll(subList)
            }
          }
        }
      }
      return list
    } catch (e: Exception) {
      e.printStackTrace()
    }
    return null
  }

  private fun getFileNameNoExtension(filePath: String): String {
    try {
      if (TextUtils.isEmpty(filePath)) return ""
      val lastPoi = filePath.lastIndexOf('.')
      val lastSep = filePath.lastIndexOf(File.separator)
      if (lastSep == -1) {
        return if (lastPoi == -1) filePath else filePath.substring(0, lastPoi)
      }
      return if (lastPoi == -1 || lastSep > lastPoi) {
        filePath.substring(lastSep + 1)
      } else filePath.substring(lastSep + 1, lastPoi)
    } catch (e: Exception) {
      e.printStackTrace()
    }
    return ""
  }
  //endregion

  //region 清所有日志
  /**
   * 清所有日志
   */
  fun clearLog() {
    try {
      deleteFilesInDir(File(fileDir))
    } catch (e: Exception) {
      e.printStackTrace()
    }
  }

  private fun deleteFilesInDir(dir: File?): Boolean {
    try {
      if (dir == null) return false
      // dir doesn't exist then return true
      if (!dir.exists()) return true
      // dir isn't a directory then return false
      if (!dir.isDirectory) return false
      val files = dir.listFiles()
      if (files != null && files.size != 0) {
        for (file in files) {
          if (file.isFile) {
            if (!file.delete()) return false
          } else if (file.isDirectory) {
            if (!deleteDir(file)) return false
          }
        }
      }
      return true
    } catch (e: Exception) {
      e.printStackTrace()
    }
    return false
  }

  private fun deleteDir(dir: File?): Boolean {
    try {
      if (dir == null) return false
      if (!dir.exists()) return true
      if (!dir.isDirectory) return false
      val files = dir.listFiles()
      if (files != null && files.isNotEmpty()) {
        for (file in files) {
          if (file.isFile) {
            if (!file.delete()) return false
          } else if (file.isDirectory) {
            if (!deleteDir(file)) return false
          }
        }
      }
      return dir.delete()
    } catch (e: Exception) {
      e.printStackTrace()
    }
    return false
  }
  //endregion

  class LoggerBuilder(context: Context) {

    private var logger: Logger = Logger(context)

    fun setIsWriteLog(
      isWriteLog: Boolean
    ): LoggerBuilder {
      logger.setIsWriteLog(isWriteLog)
      return this
    }

    fun setExpiredDay(
      expiredDay: Int
    ): LoggerBuilder {
      logger.setExpiredDay(expiredDay)
      return this
    }

    fun setFileDirPath(
      dir: String?
    ): LoggerBuilder {
      logger.setFileDirPath(dir)
      return this
    }

    fun setPrefixFlag(
      flag: String?
    ): LoggerBuilder {
      logger.setPrefixFlag(flag)
      return this
    }

    fun setSuffixFlag(
      flag: String?
    ): LoggerBuilder {
      logger.setSuffixFlag(flag)
      return this
    }

    fun build(): Logger {
      logger.clearExpiredFile()
      return logger
    }
  }

}